package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.domain.AlipayInfo;
import cn.itsource.ymcc.domain.PayFlow;
import cn.itsource.ymcc.domain.PayOrder;
import cn.itsource.ymcc.dto.AlipayNotifyDto;
import cn.itsource.ymcc.dto.PayDto;
import cn.itsource.ymcc.dto.PayResultDto;
import cn.itsource.ymcc.exception.GlobleException;
import cn.itsource.ymcc.service.IAlipayInfoService;
import cn.itsource.ymcc.service.IPayOrderService;
import cn.itsource.ymcc.service.IPayService;
import cn.itsource.ymcc.util.AssertUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class PayServiceImpl implements IPayService {
    @Autowired
    private RocketMQTemplate template;
    @Autowired
    private IPayOrderService payOrderService;
    @Autowired
    private IAlipayInfoService alipayInfoService;
    @Override
    public String apply(PayDto dto) {
        PayOrder payOrder = payOrderService.selectByOrderNo(dto.getOrderNo());
        AssertUtil.isNotNull(payOrder,"订单不存在");
        AssertUtil.isEquals(payOrder.getPayStatus(),0,"订单未支付");
        // 判断支付方式调用支付逻辑
        if(payOrder.getPayType() == 1){//支付宝
            return alipay(dto, payOrder);
        }
        return "选择支付方式";
    }

    @Override
    public String payNotify(AlipayNotifyDto dto) {
        AssertUtil.isNotEmpty(dto.getOut_trade_no(),"订单无线");

        //验证签名
        Map<String,String> map = JSON.parseObject(JSON.toJSONString(dto), Map.class);
        try {
            Boolean notify = Factory.Payment.Common().verifyNotify(map);
            AssertUtil.isTrue(notify,"验签错误");
        }catch (Exception e){
            e.printStackTrace();
        }
        //参数检查金额订单号
        PayOrder payOrder = payOrderService.selectByOrderNo(dto.getOut_trade_no());
        AssertUtil.isNotNull(payOrder,"订单无效");
        if(payOrder.getAmount().compareTo(new BigDecimal(dto.getTotal_amount())) != 0) {
            throw new GlobleException("金额错误");
        }
        //支付宝交易状态
        AssertUtil.isFalse(dto.isTradeWit(),"待支付");

        //支付单状态
        AssertUtil.isEquals(payOrder.getPayStatus(),0,"订单已处理");

        //支付宝成功，平台不成功，退款
        if (dto.isTradeSuccess() && payOrder.getPayStatus() == 2){
            try {
                Factory.Payment.Common().refund(payOrder.getOrderNo(),
                        payOrder.getAmount().toString());
                return "success";
            }catch (Exception e){
                e.printStackTrace();
                return "fail";
            }

        }

        //支付单修改
        int payStatus = dto.isTradeSuccess() ? 1 : 3;
        payOrder.setPayStatus(payStatus);
        payOrder.setUpdateTime(new Date());
        //payOrderService.updateById(payOrder);

        //保存支付流水
        PayFlow payFlow = new PayFlow();
        payFlow.setMsg(dto.getMsg());
        payFlow.setCode(dto.getCode());
        payFlow.setNotifyTime(new Date());
        payFlow.setOutTradeNo(dto.getOut_trade_no());
        payFlow.setPaySuccess(dto.isTradeSuccess());
        payFlow.setSubject(dto.getSubject());
        payFlow.setTotalAmount(payOrder.getAmount());
        payFlow.setTradeStatus(dto.getTrade_status());
        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("payOrder",payOrder);
        map1.put("payFlow",payFlow);
        //发送事务消息

        PayResultDto payResultDto = new PayResultDto(payOrder.getOrderNo(),
                dto.isTradeSuccess(),
                payOrder.getUserId(),
                payOrder.getRelationId(),
                payOrder.getExtParams());
        Message<String> build = MessageBuilder.withPayload(JSON.toJSONString(payResultDto)).build();

        TransactionSendResult alipayGroup = template.sendMessageInTransaction("alipayGroup",
                "alipay-topic:alipay-tag", build, map1);

        //获取本地事务执行状态
        LocalTransactionState state = alipayGroup.getLocalTransactionState();
        //消息发送状态
        SendStatus sendStatus = alipayGroup.getSendStatus();

        //事务执行失败需走下
        if (state != LocalTransactionState.COMMIT_MESSAGE ||
                sendStatus != SendStatus.SEND_OK){
            return "fail";
        }
        return "success";
    }

    public String alipay(PayDto dto, PayOrder payOrder){
        AlipayInfo alipayInfo = alipayInfoService.selectById(payOrder.getPayType());
        // 1. 设置参数（全局只需设置一次）

        Factory.setOptions(getOptions(alipayInfo));

        try {

            String callurl = StringUtils.isNotBlank(dto.getCallUrl()) ? dto.getCallUrl() : alipayInfo.getReturnUrl();

            // 2. 发起API调用（以创建当面付收款二维码为例）

            AlipayTradePagePayResponse response = Factory.Payment.Page().pay(
                    payOrder.getSubject(), payOrder.getOrderNo(), payOrder.getAmount().toString(), callurl);


            // 3. 处理响应或异常

            if (ResponseChecker.success(response)) {
                return response.getBody();

            } else {
                System.err.println("调用失败，原因：" + response + "，" + response);

                return "调用失败";

            }

        } catch (Exception e) {

            System.err.println("调用遭遇异常，原因：" + e.getMessage());

            throw new RuntimeException(e.getMessage(), e);

        }

    }

    private static Config getOptions(AlipayInfo alipayInfo) {

        Config config = new Config();

        config.protocol = "https";

        config.gatewayHost = "openapi.alipaydev.com";

        config.signType = "RSA2";

        config.appId = "2021000121632657";

        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中

        config.merchantPrivateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDC0U+6rEwvxq2RPbnepaV2rrnx2T+8HMb0FtId+uyh34Z5Vz6Hkm04ir7eNzbysvdKDOqwCxqplFy2VDfUWE4H/0C3CUmKOCiiR3vwdzyWWAbap7x9JqsrFJbOwqwGbBh4q3sbHQyTO56RXJp6NMZMjmY+OHlqcD/go5KEx3glQzbxC9YAH3YRHir9Gfs/he8jUXnF9AJhe8g1yZDKLRItYJpAVhgLLBu9dWv2Qsl4Cr71Q7wsAHNAiVh9IRfS4D3iTKWd2iesv6yG6lba2URcT+YL1Prfqj6vxRv55SIYzud23CVluL2dYcBiGuRk1tb9Insmeuko/vXPIfp+FVs3AgMBAAECggEABJlCQ4rLpZkQAcyuNYY9eKa5Nu9E5ODdBWgAf7qrmUqYdwbLMBIRx/LmfIJbJrF4yuOxKoSolXYuFhO42adX+DJbSbbLaJrYwrPjRhLaeEYNq12oQmAGTFcJFEpeGyy0Cy0pE8PExzjyDkZcUyQpxibaXP+iRhPuPhQ+Yin/OQnpg+LZvgJZYRhfJJH11NrUBMP8pbNzI7aERiMzOKb/sKUuzB9PvI/WsKyd1PT0MWoK3xJkEMD+8PO2PLCciDQ6NhAih9KUlZweguQkuIvz92s2xsm4Zb2Cuj+voiTwdKKdeIUN/lzxyXe9fRlCylkGL3XMQMayD/TRej7IKNR1aQKBgQD8UohLWBEzT/afCL7M2xQd522hk4sNzZZBbQkCbwnVtM5F/8xkFMdrpoplBhZpsBuUMyYUjk9R4dWXtQDqH11X0nQZd7y7Aio+oBa4fBqoua6oMNv7kYwLrYaZ0ECqRBv3CPe06wtoMoQHN9nmzVr2c4yX1SndhWrlcbQDJLX5IwKBgQDFqDd7SjZok4XU8QeL64isutA/1wxP5YkwoCF4ClihTuQrU+GY2C4z5Ln19tP7cDCmhQJ+OLzuFEr40EJlf8Fhy0d8xCGo3sJrlU0ldE+mftsguvPWMIMQyzxgbrgPpdsiN4cF1warO/KUyShaKSNr9VEYV50HOoRv1lqJsvYY3QKBgBy0xwzLWCmeT1CIjiyAQCmmyrI3Nvq7CP0oin3cZCIMD+umznoUYxu8NsKHjsU3Y+vYZdyw1BVcvBAmZ5Q7PUNgjhTXqoEcHfJCBFO4ys+nUFeSN3THekdZ1pZpOvIkDYptWsEafJG+LYcks4Wul0qymqwrdDfflenEpdY1tv5BAoGBAJMMnAJAawwQPK/4hcnF+E+xSD9GiSVjulYPu/ank9qma8AETsE8i9sVnnfsIzdb9wXbzMgFBCIHvOMxZURH8KIF7vBWpkgROgl58QQdbSiMFhBapg/C1a+H1CpWFN+nX8ksEGr61z5LgiTJJxk0o+KshqGahPucwGzHx2HMX6SNAoGBAOUuzOuNRWnAYt0mQvEDjG9tzFXVwNe+fwXcPQqIbnybMNI5lurmUBNUtaRb9GhGnrC+jr1m71+KVn5vpOpYCVCEahWoFaW07KZMqLgW3+MKXb+9ve5JRio9TIe4LfBW2tNioWX7ybMcP0RGqzdo7IEQ9JKqw6BAll252ZIzcvEB";

        //注：证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径，优先从文件系统中加载，加载失败后会继续尝试从CLASS_PATH中加载

//        config.merchantCertPath = "<-- 请填写您的应用公钥证书文件路径，例如：/foo/appCertPublicKey_2019051064521003.crt -->";
//
//        config.alipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径，例如：/foo/alipayCertPublicKey_RSA2.crt -->";
//
//        config.alipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径，例如：/foo/alipayRootCert.crt -->";

        //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可

        config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhL9hGtjeoAK9xm3AOnGLvEKlxnP6/sl8c5MxZZFvYbt7znEtFNljCBFtaOZnJtsKn7sphMDONpTMr0lN6aKT3vga6g6EM/HP1wRWywUOzWJqLbNNEJyKHL+5rfOn+d0e24tVuDI9dEw80BAVUc9NSV7coB0QMlZ+xDoKQ0iDc5dElLmB/TAmZ2bSpC8eXBiziUvexLZLyoheNPtJrmk/4ng2kHIziPOuMRfUrCZkEyh+LJ6EkhbnAikOgDMH4xWEUDtaxDyTTqhvRAyer/ARvi+F0hdi40/g12H60NO/Mle0iFQOCtMrkv+pa37hACfzv/K76rjZ4uvM33uHngXTnQIDAQAB";

        //可设置异步通知接收服务地址（可选）

        config.notifyUrl = alipayInfo.getNotifyUrl();

        //可设置AES密钥，调用AES加解密相关接口时需要（可选）

        //config.encryptKey = "<-- 请填写您的AES密钥，例如：aa4BtZ4tspm2wnXLb1ThQA== -->";

        return config;

    }
}
